package org.jeecg.common.aspect;

import lombok.extern.slf4j.Slf4j;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.jeecg.common.api.CommonAPI;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.PermissionColumn;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.util.BeanReflectionUtils;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.oConvertUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import javax.servlet.http.HttpServletRequest;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * 字段权限切面处理类 当被请求的方法有注解PermissionColumn时,会判断字段权限信息
 * 
 * @version: 1.0
 */
@Aspect
@Component
@Slf4j
public class PermissionColumnAspect {

	@Autowired
	private CommonAPI commonAPI;

	@Pointcut("@annotation(org.jeecg.common.aspect.annotation.PermissionColumn)")
	public void pointCut() {

	}

	@AfterReturning(pointcut = "pointCut()", returning = "result")
	public void afterReturning(JoinPoint point, Object result) throws Throwable {
		HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
		
		MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        PermissionColumn pc = method.getAnnotation(PermissionColumn.class);
        String component = pc.pageComponent();
        
        String requestMethod = request.getMethod();
        String requestPath = request.getRequestURI().substring(request.getContextPath().length());
        requestPath = filterUrl(requestPath);
        log.info("拦截请求 >> "+requestPath+";请求类型 >> "+requestMethod);
        String username = JwtUtil.getUserNameByToken(request);
        //查询数据权限信息
        //TODO 微服务情况下也得支持缓存机制
        List<String> fieldRules = commonAPI.queryPermission(component, requestPath, username);
        log.info("过滤权限 >> "+fieldRules);
		if (result instanceof Result) {
            if (((Result) result).getResult() instanceof IPage) {
                List<JSONObject> items = new ArrayList<>();
                parseColumnRule(items, fieldRules,((IPage) ((Result) result).getResult()).getRecords());
                log.info("分页过滤 >> ");
            }else if(((Result) result).getResult() instanceof List) {
            	List<JSONObject> items = new ArrayList<>();
                parseColumnRule(items, fieldRules, (List) ((Result) result).getResult());
                log.info("List过滤 >> ");
            }
        }
	}
	
    private void parseColumnRule(List<JSONObject> items, List<String> fieldRules, List list) {
    	Map<String, List<String>> keys = new HashMap<>();
    	for(String fieldRule : fieldRules){
    		String[] rulekeys = fieldRule.split(":");
    		if(rulekeys.length !=3){
    			continue;
    		}
    		if(keys.get(rulekeys[1]) == null){
    			keys.put(rulekeys[1], new ArrayList<String>());
    		}
    		keys.get(rulekeys[1]).add(rulekeys[2]);
    	}
    	for(Entry<String, List<String>> entry : keys.entrySet()){
    		removeUnotherField(entry.getKey(), entry.getValue(), list);
    	}
    	
	}
    
    private void removeUnotherField(String local, List<String> fieldRules, List list) {
    	if(CollectionUtils.isEmpty(list)){
    		return;
    	}
    	if("this".equals(local)){
    		for(Object o : list){
    			for(String fieldRule : fieldRules){
    				BeanReflectionUtils.setProperty(o, fieldRule, null);
    			}
        	}
    	} else {
    		List<Field> fields = BeanReflectionUtils.loadClassFields(BeanReflectionUtils.getClass(list.get(0)));
    		for(Field field : fields){
    			if(local.equals(field.getName())){
    				for(Object ob : list){
    					if(ob instanceof List){
    						removeUnotherField("this", fieldRules, (List) ob);
    					} else {
    						break;
    					}
    				}
    				break;
    			}
    		}
    	}
	}

	private String filterUrl(String requestPath){
        String url = "";
        if(oConvertUtils.isNotEmpty(requestPath)){
            url = requestPath.replace("\\", "/");
            url = requestPath.replace("//", "/");
            if(url.indexOf("//")>=0){
                url = filterUrl(url);
            }
			/*if(url.startsWith("/")){
				url=url.substring(1);
			}*/
        }
        return url;
    }
}
